home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / modula2 / cal.com / TIME.MOD < prev   
Encoding:
Modula Implementation  |  1989-06-03  |  10.7 KB  |  417 lines

  1. IMPLEMENTATION MODULE Time;
  2.  
  3.   IMPORT SYSTEM, IO, Lib, Window;
  4.  
  5.   CONST DaysPerYear = 365;
  6.         DaysPerWeek = 7;
  7.  
  8.   VAR maxDay: ARRAY Month OF CARDINAL;
  9.       daysBefore: ARRAY Month OF CARDINAL;
  10.  
  11.   PROCEDURE IsLeapYear(yr: CARDINAL): BOOLEAN;
  12.   BEGIN
  13.     RETURN (yr MOD 4 = 0) & (yr MOD 100 # 0) OR (yr MOD 400 = 0)
  14.   END IsLeapYear;
  15.  
  16.   PROCEDURE NumDays(d: Date): LONGCARD;
  17.     VAR result, leapYears: LONGCARD;
  18.   BEGIN
  19.     WITH d DO
  20.       result := LONGCARD(da);
  21.       INC( result, LONGCARD( daysBefore[mo] ) );
  22.       INC( result, (LONGCARD(yr) - 1) * DaysPerYear);
  23.       leapYears := LONGCARD((yr-1) DIV 4 - (yr-1) DIV 100 + (yr-1) DIV 400);
  24.       INC( result, leapYears );
  25.       IF (mo > Feb) & IsLeapYear(yr) THEN INC(result) END
  26.     END;
  27.     RETURN result
  28.   END NumDays;
  29.  
  30.   PROCEDURE MakeDate(n: LONGCARD; VAR d: Date);
  31.  
  32.     PROCEDURE Before(mo: Month; yr: CARDINAL): CARDINAL;
  33.       (* This routine is the procedure equivalent of
  34.          the daysBefore array - except that it corrects
  35.          for leap years.                                *)
  36.       VAR i, max: Month;
  37.           result: CARDINAL;
  38.     BEGIN
  39.       result := 0;
  40.       IF mo # Jan THEN
  41.         max := mo;
  42.         DEC(max);
  43.         FOR i := Jan TO max DO
  44.           INC(result, maxDay[i]);
  45.         END;
  46.         IF (max > Jan) & IsLeapYear(yr) THEN
  47.           INC(result)
  48.         END
  49.       END;
  50.       RETURN result
  51.     END Before;
  52.  
  53.     VAR c: CARDINAL;
  54.         i: LONGCARD;
  55.   BEGIN
  56.     WITH d DO
  57.       mo := Dec;
  58.       da := 31;
  59.       yr := CARDINAL(n DIV DaysPerYear);
  60.       i := NumDays(d);
  61.       WHILE i >= n DO
  62.         DEC(yr);
  63.         i := NumDays(d)
  64.       END;
  65.       INC(yr);
  66.       c := CARDINAL(n - i);
  67.       WHILE (mo > Jan) & (Before(mo, yr) >= c) DO
  68.         DEC(mo)
  69.       END;
  70.       DEC(c, Before(mo, yr));
  71.       da := c
  72.     END
  73.   END MakeDate;
  74.  
  75.   PROCEDURE DayOfWeek(d: Date): DayType;
  76.     CONST Offset = 0;  (* empirically determined *)
  77.   BEGIN
  78.     RETURN VAL( DayType, NumDays(d) MOD DaysPerWeek + Offset )
  79.   END DayOfWeek;
  80.  
  81. (**************************************************************************)
  82.  
  83.   MODULE Private;
  84.  
  85.     IMPORT IO, Window;                           (* modules *)
  86.     IMPORT MinYear, MaxYear, DaysPerWeek;        (* constants *)
  87.     IMPORT Date, Month;                          (* type *)
  88.     IMPORT maxDay;                               (* variables *)
  89.     IMPORT NumDays, DayOfWeek, IncDate, DecDate, (* procedures *)
  90.            IsLeapYear;
  91.  
  92.     (* EXPORT *) IMPORT GetSelDate;  (* make this visible outside *)
  93.  
  94.     CONST Margin = 1;
  95.           Between = 1;
  96.           StartRow = 4;
  97.           MaxDigits = 2;
  98.           Width = 2 * Margin + DaysPerWeek * MaxDigits +
  99.                                (DaysPerWeek-1) * Between + 2;
  100.  
  101.           Fore = Window.Black;        (* Basic black-and-white selected  *)
  102.           Back = Window.LightGray;    (*   for portability in running on *)
  103.           RevFore = Window.LightGray; (*   on different machines -       *)
  104.           RevBack = Window.Black;     (*   especially laptops.           *)
  105.           Intense = Window.White;
  106.  
  107.     VAR savedDate: Date;
  108.         minDate, maxDate: Date;
  109.  
  110.     PROCEDURE OpenWindow(): Window.WinType;
  111.       CONST Depth = 6 + 2 + StartRow - 1;
  112.             Lft = (Window.ScreenWidth - Width) DIV 2;
  113.             Top = (Window.ScreenDepth - Depth) DIV 2;
  114.             Rgt = Lft + Width - 1;
  115.             Btm = Top + Depth - 1;
  116.       VAR WD: Window.WinDef;
  117.           win: Window.WinType;
  118.     BEGIN
  119.       WITH WD DO
  120.         X1 := Lft;
  121.         Y1 := Top;
  122.         X2 := Rgt;
  123.         Y2 := Btm;
  124.         Foreground := Fore;
  125.         Background := Back;
  126.         CursorOn := FALSE;
  127.         WrapOn := FALSE;
  128.         Hidden := FALSE;
  129.         FrameOn := TRUE;
  130.         FrameDef := Window.DoubleFrame;
  131.         FrameFore := Intense;
  132.         FrameBack := Back
  133.       END;
  134.       win := Window.Open(WD);
  135.       RETURN win
  136.     END OpenWindow;
  137.  
  138.     PROCEDURE DispDay(pos0: CARDINAL; d: Date);
  139.       VAR x, y: CARDINAL;
  140.     BEGIN
  141.       x := Margin + ORD( DayOfWeek(d) ) * (MaxDigits+Between) + 1;
  142.       y := (d.da + pos0 - 1) DIV DaysPerWeek + StartRow;
  143.       Window.GotoXY(x, y);
  144.       IO.WrCard( d.da, MaxDigits )
  145.     END DispDay;
  146.  
  147.     PROCEDURE HiLite(pos0: CARDINAL; d: Date);
  148.     BEGIN
  149.       Window.TextColor( RevFore );
  150.       Window.TextBackground( RevBack );
  151.  
  152.       DispDay(pos0, d);
  153.  
  154.       Window.TextColor( Fore );
  155.       Window.TextBackground( Back )
  156.     END HiLite;
  157.  
  158.     PROCEDURE WrMonth(mo: Month);
  159.       VAR s: ARRAY [0..3] OF CHAR;
  160.     BEGIN
  161.       CASE mo OF
  162.         Jan: s := "Jan"
  163.       | Feb: s := "Feb"
  164.       | Mar: s := "Mar"
  165.       | Apr: s := "Apr"
  166.       | May: s := "May"
  167.       | Jun: s := "Jun"
  168.       | Jul: s := "Jul"
  169.       | Aug: s := "Aug"
  170.       | Sep: s := "Sep"
  171.       | Oct: s := "Oct"
  172.       | Nov: s := "Nov"
  173.       | Dec: s := "Dec"
  174.       END;
  175.       IO.WrStr(s)
  176.     END WrMonth;
  177.  
  178.     PROCEDURE LastDay(mo: Month; yr: CARDINAL): CARDINAL;
  179.       VAR da: CARDINAL;
  180.     BEGIN
  181.       da := maxDay[mo];
  182.       IF (mo = Feb) & IsLeapYear(yr) THEN INC(da) END;
  183.       RETURN da
  184.     END LastDay;
  185.  
  186.     PROCEDURE DispCalendar(d: Date; startPos: CARDINAL);
  187.  
  188.       PROCEDURE WrHeading;
  189.         CONST MonthCol = ((Width-2) - 8) DIV 2 + 1;
  190.               DayLetter = "SMTWTFS";
  191.         VAR i: CARDINAL;
  192.       BEGIN
  193.         Window.GotoXY(MonthCol, 1);
  194.         WrMonth(d.mo);
  195.         IO.WrCard(d.yr, 5);
  196.         IO.WrLn; IO.WrLn;
  197.  
  198.         Window.TextColor( Intense );
  199.  
  200.         IO.WrCharRep(' ', Margin+1);
  201.         IO.WrChar( DayLetter[0] );
  202.  
  203.         FOR i := 1 TO DaysPerWeek-1 DO
  204.           IO.WrCharRep(' ', Between+1);
  205.           IO.WrChar( DayLetter[i] )
  206.         END;
  207.  
  208.         Window.TextColor( Fore );
  209.  
  210.         IO.WrLn
  211.       END WrHeading;
  212.  
  213.       VAR i, max: CARDINAL;
  214.  
  215.     BEGIN
  216.       Window.Clear;
  217.       WrHeading;
  218.       max := LastDay(d.mo, d.yr);
  219.  
  220.       FOR i := 1 TO max DO
  221.         d.da := i;
  222.         DispDay(startPos, d)
  223.       END;
  224.  
  225.     END DispCalendar;
  226.  
  227.     PROCEDURE HandleScanCode(pos0: CARDINAL; VAR d: Date; VAR refresh: BOOLEAN);
  228.       CONST (* scan codes *)
  229.             home  = CHR(71); up    = CHR(72); pgUp  = CHR(73);
  230.             left  = CHR(75);                  right = CHR(77);
  231.             end   = CHR(79); down  = CHR(80); pgDn  = CHR(81);
  232.  
  233.             ctrlPgUp = CHR(132);
  234.             ctrlPgDn = CHR(118);
  235.  
  236.       VAR sc: CHAR; (* scan code *)
  237.           d0: Date; (* date on entry *)
  238.           max: CARDINAL;
  239.     BEGIN
  240.       d0 := d;
  241.       sc := IO.RdKey();
  242.  
  243.       CASE sc OF
  244.         left:
  245.           IF NumDays(d) > NumDays(minDate) THEN
  246.             DispDay(pos0, d);
  247.             DecDate(d, 1);
  248.             HiLite(pos0, d)
  249.           END
  250.       | right:
  251.           IF NumDays(d) < NumDays(maxDate) THEN
  252.             DispDay(pos0, d);
  253.             IncDate(d, 1);
  254.             HiLite(pos0, d)
  255.           END
  256.       | up:
  257.           IF NumDays(d) >= NumDays(minDate) + DaysPerWeek THEN
  258.             DispDay(pos0, d);
  259.             DecDate(d, DaysPerWeek);
  260.             HiLite(pos0, d)
  261.           END
  262.       | down:
  263.           IF NumDays(d) + DaysPerWeek <= NumDays(maxDate) THEN
  264.             DispDay(pos0, d);
  265.             IncDate(d, DaysPerWeek);
  266.             HiLite(pos0, d)
  267.           END
  268.       | pgUp:
  269.           IF d.mo > Jan THEN DEC(d.mo)
  270.           ELSE
  271.             IF d.yr > MinYear THEN
  272.               DEC(d.yr);
  273.               d.mo := Dec
  274.             END
  275.           END;
  276.           max := LastDay(d.mo, d.yr);
  277.           IF d.da > max THEN d.da := max END
  278.       | pgDn:
  279.           IF d.mo < Dec THEN INC(d.mo)
  280.           ELSE
  281.             IF d.yr < MaxYear THEN
  282.               INC(d.yr);
  283.               d.mo := Jan
  284.             END
  285.           END;
  286.           max := LastDay(d.mo, d.yr);
  287.           IF d.da > max THEN d.da := max END
  288.       | ctrlPgUp:
  289.           IF d.yr > MinYear THEN
  290.             DEC(d.yr);
  291.             IF (d.mo = Feb) & (d.da = 29) THEN
  292.               d.da := LastDay(d.mo, d.yr)
  293.             END
  294.           END
  295.       | ctrlPgDn:
  296.           IF d.yr < MaxYear THEN
  297.             INC(d.yr);
  298.             IF (d.mo = Feb) & (d.da = 29) THEN
  299.               d.da := LastDay(d.mo, d.yr)
  300.             END
  301.           END
  302.       | home:
  303.           DispDay(pos0, d);
  304.           d := savedDate;
  305.           HiLite(pos0, d)
  306.       END;
  307.       refresh := (d.mo # d0.mo) OR (d.yr # d0.yr)
  308.     END HandleScanCode;
  309.  
  310.     PROCEDURE GetSelDate(VAR d: Date; VAR abort: BOOLEAN);
  311.       CONST nul = 0C;
  312.             cr  = 15C;
  313.             esc = 33C;
  314.       VAR win: Window.WinType;
  315.           ch: CHAR;
  316.           refresh: BOOLEAN;      (* rebuild display *)
  317.           startPos: CARDINAL;    (* horizontal offset *)
  318.           savedDay: CARDINAL;
  319.     BEGIN
  320.       savedDate := d;
  321.       win := OpenWindow();
  322.       refresh := TRUE;
  323.       REPEAT
  324.         IF refresh THEN
  325.           savedDay := d.da;
  326.           d.da := 1;
  327.           startPos := ORD( DayOfWeek(d) );
  328.           d.da := savedDay;
  329.  
  330.           DispCalendar(d, startPos);
  331.           HiLite(startPos, d)
  332.         END;
  333.         ch := IO.RdKey();
  334.         IF ch = nul THEN HandleScanCode(startPos, d, refresh) END
  335.       UNTIL (ch = esc) OR (ch = cr);
  336.  
  337.       abort := ch = esc;
  338.       IF abort THEN d := savedDate END;
  339.       Window.Close(win)
  340.     END GetSelDate;
  341.  
  342.   BEGIN
  343.     WITH minDate DO
  344.       mo := Jan;
  345.       da := 1;
  346.       yr := MinYear
  347.     END;
  348.     WITH maxDate DO
  349.       mo := Dec;
  350.       da := 31;
  351.       yr := MaxYear
  352.     END
  353.   END Private;
  354.  
  355. (**************************************************************************)
  356.  
  357.   PROCEDURE IncDate(VAR d: Date; n: LONGCARD);
  358.     VAR i: LONGCARD;
  359.   BEGIN
  360.     WITH d DO
  361.       i := NumDays(d);
  362.       INC(i, n);
  363.       MakeDate(i, d)
  364.     END
  365.   END IncDate;
  366.  
  367.   PROCEDURE DecDate(VAR d: Date; n: LONGCARD);
  368.     VAR i: LONGCARD;
  369.   BEGIN
  370.     WITH d DO
  371.       i := NumDays(d);
  372.       DEC(i, n);
  373.       MakeDate(i, d)
  374.     END
  375.   END DecDate;
  376.  
  377.   PROCEDURE GetSysDate(VAR d: Date; VAR dayOfWeek: DayType);
  378.     VAR r: SYSTEM.Registers;
  379.   BEGIN
  380.     WITH r DO
  381.       AH := 2AH;
  382.  
  383.       Lib.Dos(r);
  384.  
  385.       dayOfWeek := DayType(AL);
  386.       d.yr := CX;
  387.       d.mo := VAL( Month, DH-1 );
  388.       d.da := CARDINAL(DL)
  389.     END
  390.   END GetSysDate;
  391.  
  392.   PROCEDURE InitData;
  393.     VAR mo: Month;
  394.   BEGIN
  395.     maxDay[Jan] := 31;
  396.     maxDay[Feb] := 28;  (* adjust for leap years later *)
  397.     maxDay[Mar] := 31;
  398.     maxDay[Apr] := 30;
  399.     maxDay[May] := 31;
  400.     maxDay[Jun] := 30;
  401.     maxDay[Jul] := 31;
  402.     maxDay[Aug] := 31;
  403.     maxDay[Sep] := 30;
  404.     maxDay[Oct] := 31;
  405.     maxDay[Nov] := 30;
  406.     maxDay[Dec] := 31;
  407.  
  408.     daysBefore[Jan] := 0;
  409.     FOR mo := Jan TO Nov DO
  410.       daysBefore[ VAL( Month, ORD(mo)+1 ) ] := daysBefore[mo] + maxDay[mo];
  411.     END
  412.   END InitData;
  413.  
  414. BEGIN
  415.   InitData
  416. END Time.
  417.